package com.demo.tool;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.demo.config.DatabaseConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @Description: SQL Server 数据库工具类
 * @Author: cyj
 * @Date: 2025-03-24
 */
@Slf4j
@Component
public class SqlServerUtil {

    @Resource
    private DatabaseConfig databaseConfig;

    /**
     * 执行 SQL 查询并返回指定数据类型的列表
     *
     * @param sql       要执行的 SQL 语句
     * @param rowMapper 行映射器，用于将 ResultSet 的一行转换为指定类型
     * @param <T>       返回的数据类型
     * @return 查询结果（List<T>）
     */
    public <T> List<T> executeQuery(String sql, Function<ResultSet, T> rowMapper) {
        List<T> resultList = new ArrayList<>();
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            // 1. 获取数据库连接
            conn = DriverManager.getConnection(
                    databaseConfig.getDbUrl(),
                    databaseConfig.getDbUser(),
                    databaseConfig.getDbPassword()
            );

            // 2. 创建 Statement 对象
            stmt = conn.createStatement();

            // 3. 执行 SQL 查询
            rs = stmt.executeQuery(sql);

            // 4. 处理查询结果
            while (rs.next()) {
                // 使用 rowMapper 将每一行数据转换为指定类型
                T row = rowMapper.apply(rs);
                resultList.add(row);
            }
        } catch (SQLException e) {
            log.error("执行 SQL 查询失败", e);
            throw new RuntimeException("执行 SQL 查询失败", e);
        } finally {
            // 5. 关闭资源
            closeResources(rs, stmt, conn);
        }

        return resultList;
    }

    /**
     * 执行 SQL 查询并返回 JSON 格式的字符串
     *
     * @param sql 要执行的 SQL 语句
     * @return JSON 格式的查询结果
     */
    public String executeQueryToJson(String sql) {
        List<Map<String, Object>> resultList = executeQuery(sql);

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(resultList);
        } catch (Exception e) {
            log.error("JSON 转换失败", e);
            throw new RuntimeException("JSON 转换失败", e);
        }
    }

    /**
     * 执行 SQL 查询并返回 List<Map<String, Object>> 类型的结果
     *
     * @param sql 要执行的 SQL 语句
     * @return 查询结果（List<Map<String, Object>>）
     */
    public List<Map<String, Object>> executeQuery(String sql) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            // 1. 获取数据库连接
            conn = DriverManager.getConnection(
                    databaseConfig.getDbUrl(),
                    databaseConfig.getDbUser(),
                    databaseConfig.getDbPassword()
            );

            // 2. 创建 Statement 对象
            stmt = conn.createStatement();

            // 3. 执行 SQL 查询
            rs = stmt.executeQuery(sql);

            // 4. 处理查询结果
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            while (rs.next()) {
                Map<String, Object> rowMap = new HashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = metaData.getColumnName(i).toLowerCase(); // 列名转小写
                    Object columnValue = rs.getObject(i); // 获取列值
                    rowMap.put(columnName, columnValue);
                }
                resultList.add(rowMap);
            }
        } catch (SQLException e) {
            log.error("执行 SQL 查询失败", e);
            throw new RuntimeException("执行 SQL 查询失败", e);
        } finally {
            // 5. 关闭资源
            closeResources(rs, stmt, conn);
        }

        return resultList;
    }

    /**
     * 关闭数据库资源
     *
     * @param rs   ResultSet
     * @param stmt Statement
     * @param conn Connection
     */
    private void closeResources(ResultSet rs, Statement stmt, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            log.error("关闭数据库资源失败", e);
        }
    }
}